/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <cstdint>
#include <string>
#include <memory>
#include "utils_noncopyable.h"
#include "common_media_define.h"
#include "media_stream.h"

namespace El {
namespace StreamService {

// 前向声明
class StreamFlowControl;

/**
 * @brief GstBuffer释放回调的用户数据结构
 *
 * 用于在GstBuffer释放时通知流控管理器。
 * 统一使用shared_ptr管理flowControl的生命周期。
 */
struct BufferReleaseContext {
    Media::MediaFramePtr framePtr;                  ///< 保持MediaFrame引用
    std::shared_ptr<StreamFlowControl> flowControl; ///< 流控管理器
    bool isVideo;                                   ///< 是否是视频帧

    // 统一的构造函数: 使用shared_ptr管理flowControl
    BufferReleaseContext(const Media::MediaFramePtr &frame, const std::shared_ptr<StreamFlowControl> &fc, bool video)
        : framePtr(frame), flowControl(fc), isVideo(video)
    {
    }
};

/**
 * @brief 流媒体推送流控管理器
 *
 * 提供基于帧计数的流量控制，防止推送缓存溢出导致内存耗尽。
 * 特点：
 * - 应用层精确计数：通过推送/释放计数器追踪实际缓存帧数
 * - GOP完整性保证：丢帧后等待I帧才恢复推送，避免推送残缺GOP
 * - 独立视频/音频控制：视频和音频使用独立的阈值和策略
 */
class StreamFlowControl {
    DISALLOW_COPY_AND_MOVE(StreamFlowControl);

public:
    /**
     * @brief 流控决策结果
     */
    enum class Decision {
        ACCEPT,   // 接受该帧
        DROP,     // 丢弃该帧
    };

    /**
     * @brief 流控统计信息
     */
    struct Statistics {
        uint64_t videoPushedFrames{0};     // 视频推送帧总数
        uint64_t videoReleasedFrames{0};   // 视频释放帧总数
        uint64_t videoBufferedFrames{0};   // 视频当前缓存帧数
        uint64_t videoDroppedFrames{0};    // 视频累计丢帧数

        uint64_t audioPushedFrames{0};     // 音频推送帧总数
        uint64_t audioReleasedFrames{0};   // 音频释放帧总数
        uint64_t audioBufferedFrames{0};   // 音频当前缓存帧数
        uint64_t audioDroppedFrames{0};    // 音频累计丢帧数

        bool videoWaitingIFrame{false};    // 是否正在等待I帧恢复
    };

public:
    /**
     * @brief 构造函数
     * @param name 流控实例名称（用于日志标识）
     * @param maxVideoFrames 视频最大缓存帧数（默认20帧）
     * @param maxAudioFrames 音频最大缓存帧数（默认50帧）
     */
    explicit StreamFlowControl(const std::string &name, uint32_t maxVideoFrames = 20,
                               uint32_t maxAudioFrames = 50);

    ~StreamFlowControl() = default;

    /**
     * @brief 检查是否应接受该帧
     * @param frame 媒体帧指针
     * @return 流控决策（ACCEPT/DROP）
     */
    Decision ShouldAcceptFrame(const Media::MediaFramePtr &frame);

    /**
     * @brief 通知帧已成功推送
     * @param isVideo 是否是视频帧
     */
    void OnFramePushed(bool isVideo);

    /**
     * @brief 通知帧已被释放
     * @param isVideo 是否是视频帧
     */
    void OnFrameReleased(bool isVideo);

    /**
     * @brief 获取统计信息
     * @return 当前统计数据
     */
    Statistics GetStatistics() const;

    /**
     * @brief 重置所有计数器
     */
    void Reset();

    /**
     * @brief 设置日志间隔（每N帧丢弃输出一次警告）
     * @param interval 日志间隔帧数（默认100）
     */
    void SetLogInterval(uint32_t interval);

private:
    std::string name_;              // 实例名称
    uint32_t maxVideoFrames_;       // 视频最大缓存帧数
    uint32_t maxAudioFrames_;       // 音频最大缓存帧数
    uint32_t logInterval_;          // 日志输出间隔

    // 视频帧计数
    uint64_t videoPushedFrames_{0};
    uint64_t videoReleasedFrames_{0};
    uint64_t videoDroppedFrames_{0};

    // 音频帧计数
    uint64_t audioPushedFrames_{0};
    uint64_t audioReleasedFrames_{0};
    uint64_t audioDroppedFrames_{0};
};

} // namespace StreamService
} // namespace El
